package com.rainbow.common.handler.auth;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.rainbow.common.core.constant.Constant;
import com.rainbow.common.core.entity.Result;
import com.rainbow.common.core.error.GlobalException;
import com.rainbow.common.core.toolkit.ContextHolder;
import com.rainbow.common.handler.properties.HandleProperties;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.skywalking.apm.toolkit.trace.Trace;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.*;
import org.springframework.lang.Nullable;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;


/**
 * 配置全局拦截器
 * 添加MDC，权限到header
 * http://logback.qos.ch/manual/mdc.html#managedThreads
 * @author 傅为地
 */
@Slf4j
@Configuration
@EnableConfigurationProperties(HandleProperties.class)
@ConditionalOnProperty(prefix=Constant.RAINBOW_COMMON_AUTH_PREFIX,name = "enable", havingValue = "true",matchIfMissing = true)
public class AuthInterceptor extends HandlerInterceptorAdapter {

    @Resource
    private HandleProperties handleProperties;

    @Resource
    private RestTemplate restTemplate;

    @Override
    @Trace
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        if (!ObjectUtils.isEmpty(handleProperties) && handleProperties.getAuth().isEnable()) {
            //白名单,默认排除error路径
            List<String> whiteAddressList = Lists.newArrayList("/error");
            //拒绝黑名单路径
            List<String> blockAddressList = new ArrayList<>();
            //白名单放行路径
            if (CollectionUtils.isNotEmpty(handleProperties.getAuth().getIncludes())) {
                whiteAddressList.addAll(handleProperties.getAuth().getIncludes());
                whiteAddressList = whiteAddressList.stream().filter(ObjectUtils::isNotEmpty).distinct().collect(Collectors.toList());
            }
            if (!ObjectUtils.isEmpty(whiteAddressList)) {
                whiteAddressList = whiteAddressList.stream().filter(t -> !ObjectUtils.isEmpty(t)).distinct().collect(Collectors.toList());
                PathMatcher pathMatcher = new AntPathMatcher();
                for (String ignoreUrl : whiteAddressList) {
                    if (pathMatcher.match(ignoreUrl, request.getRequestURI())) {
                        return true;
                    }
                }
            }
            //黑名单拒绝路径
            if (CollectionUtils.isNotEmpty(handleProperties.getAuth().getExcludes())) {
                blockAddressList.addAll(handleProperties.getAuth().getExcludes());
                blockAddressList = blockAddressList.stream().filter(org.apache.commons.lang3.ObjectUtils::isNotEmpty).distinct().collect(Collectors.toList());
            }
            if (!ObjectUtils.isEmpty(blockAddressList)) {
                blockAddressList = blockAddressList.stream().filter(t -> !ObjectUtils.isEmpty(t)).distinct().collect(Collectors.toList());
                PathMatcher pathMatcher = new AntPathMatcher();
                for (String ignoreUrl : blockAddressList) {
                    if (pathMatcher.match(ignoreUrl, request.getRequestURI())) {
                        return false;
                    }
                }
            }
            //遇到白名单token时直接放行
            List<String> whiteToken=handleProperties.getAuth().getSkiptokens();
            if(!ObjectUtils.isEmpty(whiteToken)){
                for (String item:whiteToken) {
                    if(!ObjectUtils.isEmpty(item)&&Objects.equals(item,request.getHeader(Constant.AUTHORIZATION))){
                        return true;
                    }
                }
            }
            //调用AUTH验证权限，需要传递token和clientId,后续看情况是否加上版本信息
            HttpHeaders headers = new HttpHeaders();
            headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
            if(StringUtils.isNotBlank(request.getHeader(Constant.AUTHORIZATION))){
                headers.add(Constant.AUTHORIZATION, request.getHeader(Constant.AUTHORIZATION));
            }
            if(StringUtils.isNotBlank(request.getHeader(Constant.USER_TOKEN_CLIENT_ID))){
                headers.add(Constant.USER_TOKEN_CLIENT_ID, request.getHeader(Constant.USER_TOKEN_CLIENT_ID));
            }
            ResponseEntity<Result> responseEntity = restTemplate.exchange(handleProperties.getAuth().getAddress() + "?" + Constant.USER_TOKEN_PERMISSION + "=" + request.getRequestURI(), HttpMethod.GET, new HttpEntity<Map<String, Object>>(null, headers), Result.class);
            if (responseEntity.getStatusCode().equals(HttpStatus.OK)) {
                Result result = responseEntity.getBody();
                if (!ObjectUtils.isEmpty(result)) {
                    if (result.getCode().equals(HttpStatus.OK.value()) && result.getData().equals(true)) {
                        //权限验证通过,返回用户数据
                        ContextHolder.getInstance().put(Constant.CURRENT_LOGIN_USER, JSON.parseObject(result.getMessage()));
                        return true;
                    }
                    throw new GlobalException(result.getMessage(), HttpStatus.UNAUTHORIZED.value(), result.getData());
                } else {
                    throw new GlobalException("认证结果为空", HttpStatus.UNAUTHORIZED.value());
                }
            } else {
                throw new GlobalException("资源认证失败", HttpStatus.UNAUTHORIZED.value());
            }
        }
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
        super.postHandle(request,response,handler,modelAndView);
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
        ContextHolder.getInstance().remove(Constant.CURRENT_LOGIN_USER);
        super.afterCompletion(request,response,handler,ex);
    }


}
